#include <common.h>
#include <proc.h>
#include "syscall.h"
#include <time.h>
#include <sys/time.h>
#define   SYS_exit    0
#define   SYS_yield   1 
#define   SYS_open    2
#define   SYS_read    3
#define   SYS_write   4
#define   SYS_kill    5
#define   SYS_getpid  6
#define   SYS_close   7
#define   SYS_lseek   8
#define   SYS_brk     9
#define   SYS_fstat   10
#define   SYS_time    11
#define   SYS_signal  12
#define   SYS_execve  13
#define   SYS_fork    14
#define   SYS_link    15
#define   SYS_unlink  16
#define   SYS_wait    17
#define   SYS_times   18
#define   SYS_gettimeofday  19
// #define SYS_yield 1
// #define SYS_exit 0
void do_yield(){
  printf("yield");
}
extern void halt(int code);
// int write(int fd, void *buf, size_t count){
//   // printf("fd = %d",fd);
//   // printf("count = %d",count);
//   if (fd != 1)
//   {
//     /* code */
//     return -1;
//   }
//   printf("%s",buf);
//   return count;
  
// }

int my_gettimeofday(struct timeval *tv, struct timezone *tz){
  uint64_t us = io_read(AM_TIMER_UPTIME).us;
  if (tv)
  {
    tv->tv_sec= us / 1000000;
    tv->tv_usec = us % 1000000;
  }
   
  return 0;
}
extern int fs_open(const char *pathname, int flags, int mode);
extern size_t fs_read(int fd, void *buf, size_t len);
extern size_t fs_write(int fd, const void *buf, size_t len);
extern size_t fs_lseek(int fd, size_t offset, int whence);
extern int fs_close(int fd);
extern void naive_uload(PCB *pcb, const char *filename) ;
void do_syscall(Context *c) {
  uintptr_t a[4];
  a[0] = c->GPR1;
  a[1] = c->GPR2;
  a[2] = c->GPR3;
  a[3] = c->GPR4;
  // printf("a[0]=%d",a[0]);
  switch (a[0]) {
    case SYS_yield:do_yield();break;
    case SYS_exit:halt(0);break;
    case SYS_brk:c->GPRx=0;break;
    case SYS_open:c->GPRx = fs_open((char *)a[1],(int)a[2],(int)a[3]); break;
    case SYS_read:c->GPRx = fs_read((int)a[1],(void *)a[2],(size_t)a[3]);break;
    case SYS_write:c->GPRx = fs_write((int)a[1],(void *)a[2],(size_t)a[3]);break;
    case SYS_lseek:c->GPRx = fs_lseek((int)a[1],(size_t)a[2],(int)a[3]);break;
    case SYS_close:c->GPRx = fs_close((int)a[1]);break;
    case SYS_gettimeofday:c->GPRx = my_gettimeofday((struct timeval *)a[1],(struct timezone *)a[2]);break;
    case SYS_execve: naive_uload(NULL,(char *)a[1]);
    default: panic("Unhandled syscall ID = %d", a[0]);
  }
}
